import {Injectable} from '@angular/core';
import {HttpClient, HttpParams} from '@angular/common/http';
import {interval, Observable} from 'rxjs';
import {ApiService} from '../../api/api.service';
import {SimpleJsonFormatter} from '../../formatter/simple-json-formatter';
import {Page} from './page';
import {take} from 'rxjs/internal/operators';

const _page = 'page';
const _pageSize = 'page_size';

@Injectable()
export class PaginationService {
  public page = new Page();
  public pageNumber = 1;
  public pageSize = 20;
  public readonly dataLoadSubscriber$: Observable<Page>;
  private _url: string;
  public simpleFormatter: SimpleJsonFormatter[];
  private _queryParams: { key: string, value: any, op?: 's' | 'a' }[] = [];
  private _options: { [key: string]: any, observe: 'response', params?: any } = {observe: 'response'};
  private _httpParams: HttpParams;

  constructor(private http: HttpClient, public apiService: ApiService) {
    this._url = '';
    /** 创建可观察对象 */
    this.dataLoadSubscriber$ = this.dataLoadObserver();
  }

  get url(): string {
    return this._url;
  }

  set url(value: string) {
    this._url = value;
  }

  /**
   * 生成一个Page的可观察对象, 确保page对象是可用状态。
   * */
  private dataLoadObserver(): Observable<Page> {
    return new Observable((observer) => {
      const i = interval(50).pipe(take(600)).subscribe((val) => {
        if (this.page && this.page.ready) {
          i.unsubscribe();
          observer.next(this.page);
          observer.complete();
        }
        if (this.page && this.page.error) {
          i.unsubscribe();
          observer.error(this.page.error);
        }
        if (val >= 599) {
          i.unsubscribe();
          observer.error(`request ${this._url} timeout`);
        }
      });
    });
  }

  /** 初始化 */
  init(simpleFormatter?: SimpleJsonFormatter[]): void {
    this.simpleFormatter = simpleFormatter;
    /** 替换分页参数 */
    this.loadData();
  }

  /** 加载分页数据 */
  loadData(): void {
    this.replacePageParamsHandler();
    /** 重置page状态 */
    this.page.ready = false;
    /** 请求数据 */
    this.apiService.get(this._url, this._options).subscribe((res: any) => {
      this.page.results = res.body.results;
      this.page.count = res.body.count;
      this.page.previous = res.body.previous;
      this.page.next = res.body.next;
      this.page.current = res.url;
      this.page.pageNumber = this.pageNumber;
      this.page.pageSize = this.pageSize;
      const floor = Math.floor((this.page.count / this.pageSize));
      this.page.totalPage = (this.page.count % this.pageSize) > 0 ? floor + 1 : floor;
      if (this.simpleFormatter) {
        this.formatData();
      }
      this.page.ready = true;
    }, (resp) => {
      this.page.ready = false;
      this.page.error = resp.error.msg;
    });
  }

  setPageParam(page: number, pageSize: number): void {
    this.pageNumber = page;
    this.pageSize = pageSize;
  }

  set queryParams(params: { key: string, value: any, op?: 's' | 'a' }[]) {
    if (params.length === 0) {
      this._queryParams = [];
      return;
    }
    for (const param of params) {
      this._queryParams.push(param);
    }
  }

  /**
   * 格式化要输出的数据 如：时间等
   * */
  formatData() {
    this.page.formattedResults = SimpleJsonFormatter.formatDataSet(this.simpleFormatter, this.page.results);
    this.page.ready = true;
  }

  /**
   * 分页参数替换函数
   * */
  replacePageParams() {
    this._httpParams = new HttpParams().set(
      _page, this.pageNumber.toString()
    ).set(
      _pageSize, this.pageSize.toString()
    );
  }

  replaceQueryParams() {
    for (const param of this._queryParams) {
      if (!param.op) {
        param.op = 's';
      }
      if (param.op === 'a') {
        this._httpParams = this._httpParams.append(param.key, param.value);
      } else if (param.op === 's') {
        this._httpParams = this._httpParams.set(param.key, param.value);
      }
    }
  }

  replacePageParamsHandler() {
    this.replacePageParams();
    this.replaceQueryParams();
    this._options.params = this._httpParams;
  }

  previousPage(): void {
    this.dataLoadSubscriber$.subscribe(() => {
      if (this.pageNumber > 1) {
        this.pageNumber -= 1;
        this.loadData();
      }
    });
  }

  nextPage(): void {
    this.dataLoadSubscriber$.subscribe(() => {
      if (this.pageNumber < this.page.totalPage) {
        this.pageNumber += 1;
        this.loadData();
      }
    });
  }

  firstPage(): void {
    this.dataLoadSubscriber$.subscribe(() => {
      if (this.pageNumber !== 1) {
        this.pageNumber = 1;
        this.loadData();
      }
    });
  }

  lastPage(): void {
    this.dataLoadSubscriber$.subscribe(() => {
      if (this.pageNumber !== this.page.totalPage) {
        this.pageNumber = this.page.totalPage;
        this.loadData();
      }
    });
  }

  reload(): void {
    this.dataLoadSubscriber$.subscribe((next) => {
      this.pageNumber = 1;
      this.loadData();
    });
  }

  refresh(pageNumber?: number): void {
    this.dataLoadSubscriber$.subscribe(() => {
      if (pageNumber) {
        this.pageNumber = pageNumber;
      }
      this.loadData();
    });
  }

}

export let paginationFactory = (http: HttpClient, apiService: ApiService) => {
  return new PaginationService(http, apiService);
};
